﻿#include "rtsp-server.hpp"
#include "../../liblive2d/include/catlive2d.hpp"
#include "../../libcat/include/cat-window.hpp"


#include "xop/RtspServer.h"
#include "net/Timer.h"
#include <thread>
#include <memory>
#include <iostream>
#include <string>
#include <GL\glew.h>
#include "avcodec/h264_encoder.h"
#include <net\Timestamp.h>

namespace{
	RtspServer* s_instance = NULL;

	static std::shared_ptr<xop::EventLoop> event_loop;
	static std::shared_ptr<xop::RtspServer> server;
	static ffmpeg::H264Encoder h264_encoder;
	static uint8_t * buffer;

	bool IsKeyFrame(const uint8_t* data, uint32_t size)
	{
		if (size > 4) {
			//0x67:sps ,0x65:IDR, 0x6: SEI
			if (data[4] == 0x67 || data[4] == 0x65 || data[4] == 0x6) {
				return true;
			}
		}

		return false;
	}

	void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id)
	{
		int width, height;
		width = RtspServer::GetInstance()->getWidth();
		height = RtspServer::GetInstance()->getHeight();

		static xop::Timestamp tp, tp2;
		uint32_t msec = 1000 / 30;

		uint32_t buffer_size = width * height * 4;
		std::shared_ptr<uint8_t> sbuffer(new uint8_t[buffer_size]);

		while (RtspServer::GetInstance()->IsInit()) {
			if (tp2.elapsed() >= 1000) {
				tp2.reset();
			}

			uint32_t delay = msec;
			uint32_t elapsed = (uint32_t)tp.elapsed(); /*编码耗时计算*/
			if (elapsed > delay) {
				delay = 0;
			}
			else {
				delay -= elapsed;
			}

			std::this_thread::sleep_for(std::chrono::milliseconds(delay));
			tp.reset();

			int frame_size = 0;
			uint32_t timestamp = xop::H264Source::GetTimestamp();
			for(int x = 0;x<width;x++)
			{
			 for (int y = 0; y < height; y++)
			 {
				 sbuffer.get()[x * 4 + y * width * 4] = buffer[x * 4 +(height - y) * width * 4];
				 sbuffer.get()[x * 4 + 1 + y * width * 4] = buffer[x * 4 + 1 + (height - y) * width * 4];
				 sbuffer.get()[x * 4 + 2 + y * width * 4] = buffer[x * 4 + 2 + (height - y) * width * 4];
				 sbuffer.get()[x * 4 + 3 + y * width * 4] = buffer[x * 4 + 3 + (height - y) * width * 4];
			 }
			}
			ffmpeg::AVPacketPtr pkt_ptr = h264_encoder.Encode(sbuffer.get(), width, height);
			int extra_data_size = 0;
			uint8_t* extra_data = nullptr;

			if (pkt_ptr != nullptr) {
				if (IsKeyFrame(pkt_ptr->data, pkt_ptr->size)) {
					/* 编码器使用了AV_CODEC_FLAG_GLOBAL_HEADER, 这里需要添加sps, pps */
					extra_data = h264_encoder.GetAVCodecContext()->extradata;
					extra_data_size = h264_encoder.GetAVCodecContext()->extradata_size;
					memcpy(sbuffer.get(), extra_data, extra_data_size);
				}

				memcpy(sbuffer.get() + extra_data_size, pkt_ptr->data, pkt_ptr->size);
				frame_size = pkt_ptr->size + extra_data_size;
			}
			
			if (frame_size>0) {
				xop::AVFrame vidoe_frame(frame_size);
				vidoe_frame.size = frame_size - 4; /* -4 去掉H.264起始码 */
				vidoe_frame.type = IsKeyFrame(sbuffer.get(), frame_size) ? xop::VIDEO_FRAME_I : xop::VIDEO_FRAME_P;
				vidoe_frame.timestamp = timestamp;
				memcpy(vidoe_frame.buffer.get(), sbuffer.get() + 4, frame_size - 4);
				rtsp_server->PushFrame(session_id, xop::channel_0, vidoe_frame);
			}
		};
		rtsp_server->Stop();
	}

	static std::thread* t1 = NULL;
}

RtspServer* RtspServer::GetInstance()
{
	if (s_instance == NULL)
	{
		s_instance = new RtspServer();
	}
	return s_instance;
}

void RtspServer::ReleaseInstance()
{
	if (s_instance != NULL)
	{
		delete s_instance;
	}
	s_instance = NULL;
}

void RtspServer::Init(Json::Value cfg)
{
		windowWidth = cfg["decoration"]["window_size"][0].asInt();
		windowHeight = cfg["decoration"]["window_size"][1].asInt();

		buffer = new uint8_t[4 * windowWidth * windowHeight];

		int port = cfg["network"]["send_port"].asInt();

		event_loop = std::shared_ptr<xop::EventLoop>(new xop::EventLoop());		
		server = xop::RtspServer::Create(event_loop.get());

		if (!server->Start("0.0.0.0", port)) {
			printf("RTSP Server listen on %d failed.\n", port);
			return;
		}
		xop::MediaSession* session = xop::MediaSession::CreateNew("live");
		session->AddSource(xop::channel_0, xop::H264Source::CreateNew());
		//session->StartMulticast(); 
		session->SetNotifyCallback([](xop::MediaSessionId session_id, uint32_t clients) {
			std::cout << "The number of rtsp clients: " << clients << std::endl;
			});

		xop::MediaSessionId session_id = server->AddSession(session);

		char buff[100];
		sprintf_s(buff, "rtsp://127.0.0.1:%d/live", port);
		MessageBox(NULL, buff, "RTSP SERVER", MB_OK | MB_ICONQUESTION);

		ffmpeg::AVConfig encoder_config;
		encoder_config.video.framerate = 30;
		encoder_config.video.bitrate = 8000000;
		encoder_config.video.gop = 30;
		encoder_config.video.format = AV_PIX_FMT_RGBA;
		encoder_config.video.width = windowWidth;
		encoder_config.video.height = windowHeight;
		h264_encoder.Init(encoder_config);

		t1 = new std::thread(SendFrameThread, server.get(), session_id);

		isInit = true;
}

void RtspServer::Draw(void* _window)
{
	glReadPixels(0, 0, windowWidth, windowHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
}

void RtspServer::Release()
{
	isInit = false;
	if (t1) {
		t1->join();
		t1 = nullptr;
	}
}

RtspServer::RtspServer()
{
	
}

RtspServer::~RtspServer()
{
	
}

